package com.kexio.log.analytics.adapter;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import com.kexio.log.analytics.service.LogMetricsCollector;

/**
 * LoggingAspect 适配器
 * 
 * 与现有的 LoggingAspect 集成，提供非侵入式的日志分析功能
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Component
@ConditionalOnClass(name = "com.kexio.auth.aop.LoggingAspect")
@ConditionalOnProperty(prefix = "kexio.log.analytics", name = "enabled", havingValue = "true")
public class LoggingAspectAdapter {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspectAdapter.class);
    
    @Autowired(required = false)
    private LogMetricsCollector metricsCollector;
    
    // 日志统计
    private final AtomicLong totalLogs = new AtomicLong(0);
    private final AtomicLong errorLogs = new AtomicLong(0);
    private final AtomicLong warnLogs = new AtomicLong(0);
    private final AtomicLong infoLogs = new AtomicLong(0);
    
    // 按类和方法统计
    private final Map<String, AtomicLong> methodCalls = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> methodExecutionTimes = new ConcurrentHashMap<>();
    private final Map<String, AtomicLong> methodErrors = new ConcurrentHashMap<>();
    
    /**
     * 初始化适配器
     */
    public void initialize() {
        try {
            logger.info("初始化 LoggingAspect 适配器");
            
            if (metricsCollector != null) {
                logger.info("日志指标收集器已启用");
            }
            
        } catch (Exception e) {
            logger.warn("LoggingAspect 适配器初始化失败: {}", e.getMessage());
        }
    }
    
    /**
     * 记录方法执行日志
     * 
     * @param className 类名
     * @param methodName 方法名
     * @param layer 层级 (CONTROLLER, SERVICE, MAPPER)
     * @param executionTime 执行时间 (毫秒)
     * @param isSuccess 是否成功
     * @param exception 异常信息 (如果有)
     */
    public void recordMethodExecution(String className, String methodName, String layer,
                                     long executionTime, boolean isSuccess, Throwable exception) {
        try {
            totalLogs.incrementAndGet();
            
            String methodKey = className + "." + methodName;
            methodCalls.computeIfAbsent(methodKey, k -> new AtomicLong(0)).incrementAndGet();
            methodExecutionTimes.computeIfAbsent(methodKey, k -> new AtomicLong(0)).addAndGet(executionTime);
            
            if (!isSuccess && exception != null) {
                errorLogs.incrementAndGet();
                methodErrors.computeIfAbsent(methodKey, k -> new AtomicLong(0)).incrementAndGet();
            }
            
            // 委托给指标收集器
            if (metricsCollector != null) {
                metricsCollector.recordMethodExecution(
                    className, methodName, layer, executionTime, isSuccess, exception
                );
            }
            
            // 记录慢方法
            if (executionTime > 2000) { // 超过 2 秒的方法
                logger.warn("方法执行较慢: {}.{} [{}] - {}ms", 
                           className, methodName, layer, executionTime);
            }
            
        } catch (Exception e) {
            logger.error("记录方法执行日志失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 记录控制器请求日志
     * 
     * @param requestPath 请求路径
     * @param method HTTP 方法
     * @param responseTime 响应时间
     * @param statusCode HTTP 状态码
     * @param userAgent 用户代理
     * @param clientIp 客户端 IP
     */
    public void recordControllerRequest(String requestPath, String method, long responseTime,
                                       int statusCode, String userAgent, String clientIp) {
        try {
            totalLogs.incrementAndGet();
            
            if (statusCode >= 500) {
                errorLogs.incrementAndGet();
            } else if (statusCode >= 400) {
                warnLogs.incrementAndGet();
            } else {
                infoLogs.incrementAndGet();
            }
            
            // 委托给指标收集器
            if (metricsCollector != null) {
                metricsCollector.recordControllerRequest(
                    requestPath, method, responseTime, statusCode, userAgent, clientIp
                );
            }
            
            // 记录慢请求
            if (responseTime > 3000) { // 超过 3 秒的请求
                logger.warn("请求响应较慢: {} {} - {}ms [{}]", 
                           method, requestPath, responseTime, statusCode);
            }
            
        } catch (Exception e) {
            logger.error("记录控制器请求日志失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 记录异常日志
     * 
     * @param className 类名
     * @param methodName 方法名
     * @param exception 异常
     * @param context 上下文信息
     */
    public void recordException(String className, String methodName, Throwable exception, String context) {
        try {
            errorLogs.incrementAndGet();
            
            String methodKey = className + "." + methodName;
            methodErrors.computeIfAbsent(methodKey, k -> new AtomicLong(0)).incrementAndGet();
            
            // 委托给指标收集器
            if (metricsCollector != null) {
                metricsCollector.recordException(className, methodName, exception, context);
            }
            
            logger.error("记录异常: {}.{} - {}: {}", 
                        className, methodName, exception.getClass().getSimpleName(), exception.getMessage());
            
        } catch (Exception e) {
            logger.error("记录异常日志失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 分析用户行为模式
     * 
     * @param userId 用户ID
     * @param action 操作
     * @param resource 资源
     * @param timestamp 时间戳
     */
    public void analyzeUserBehavior(String userId, String action, String resource, LocalDateTime timestamp) {
        try {
            // 委托给指标收集器进行行为分析
            if (metricsCollector != null) {
                metricsCollector.analyzeUserBehavior(userId, action, resource, timestamp);
            }
            
        } catch (Exception e) {
            logger.error("用户行为分析失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 获取日志统计信息
     * 
     * @return 日志统计数据
     */
    public LogStatistics getStatistics() {
        try {
            long total = totalLogs.get();
            long errors = errorLogs.get();
            long warns = warnLogs.get();
            long infos = infoLogs.get();
            
            double errorRate = total > 0 ? (double) errors / total : 0.0;
            
            return new LogStatistics(
                total, errors, warns, infos, errorRate,
                new ConcurrentHashMap<>(methodCalls),
                calculateAverageExecutionTime(),
                new ConcurrentHashMap<>(methodErrors),
                LocalDateTime.now()
            );
            
        } catch (Exception e) {
            logger.error("获取日志统计失败: {}", e.getMessage(), e);
            return new LogStatistics();
        }
    }
    
    /**
     * 计算平均执行时间
     */
    private Map<String, Double> calculateAverageExecutionTime() {
        Map<String, Double> avgTimes = new ConcurrentHashMap<>();
        
        for (Map.Entry<String, AtomicLong> entry : methodExecutionTimes.entrySet()) {
            String method = entry.getKey();
            long totalTime = entry.getValue().get();
            long count = methodCalls.getOrDefault(method, new AtomicLong(0)).get();
            
            if (count > 0) {
                avgTimes.put(method, (double) totalTime / count);
            }
        }
        
        return avgTimes;
    }
    
    /**
     * 重置统计数据
     */
    public void resetStatistics() {
        totalLogs.set(0);
        errorLogs.set(0);
        warnLogs.set(0);
        infoLogs.set(0);
        methodCalls.clear();
        methodExecutionTimes.clear();
        methodErrors.clear();
        
        logger.info("日志统计数据已重置");
    }
    
    /**
     * 检查适配器是否可用
     * 
     * @return 是否可用
     */
    public boolean isAvailable() {
        return metricsCollector != null;
    }
    
    /**
     * 日志统计信息
     */
    public static class LogStatistics {
        private long totalLogs;
        private long errorLogs;
        private long warnLogs;
        private long infoLogs;
        private double errorRate;
        private Map<String, AtomicLong> methodCalls;
        private Map<String, Double> averageExecutionTime;
        private Map<String, AtomicLong> methodErrors;
        private LocalDateTime timestamp;
        
        public LogStatistics() {
            this.timestamp = LocalDateTime.now();
            this.methodCalls = new ConcurrentHashMap<>();
            this.averageExecutionTime = new ConcurrentHashMap<>();
            this.methodErrors = new ConcurrentHashMap<>();
        }
        
        public LogStatistics(long totalLogs, long errorLogs, long warnLogs, long infoLogs,
                            double errorRate, Map<String, AtomicLong> methodCalls,
                            Map<String, Double> averageExecutionTime, Map<String, AtomicLong> methodErrors,
                            LocalDateTime timestamp) {
            this.totalLogs = totalLogs;
            this.errorLogs = errorLogs;
            this.warnLogs = warnLogs;
            this.infoLogs = infoLogs;
            this.errorRate = errorRate;
            this.methodCalls = methodCalls;
            this.averageExecutionTime = averageExecutionTime;
            this.methodErrors = methodErrors;
            this.timestamp = timestamp;
        }
        
        // Getters and Setters
        public long getTotalLogs() { return totalLogs; }
        public void setTotalLogs(long totalLogs) { this.totalLogs = totalLogs; }
        
        public long getErrorLogs() { return errorLogs; }
        public void setErrorLogs(long errorLogs) { this.errorLogs = errorLogs; }
        
        public long getWarnLogs() { return warnLogs; }
        public void setWarnLogs(long warnLogs) { this.warnLogs = warnLogs; }
        
        public long getInfoLogs() { return infoLogs; }
        public void setInfoLogs(long infoLogs) { this.infoLogs = infoLogs; }
        
        public double getErrorRate() { return errorRate; }
        public void setErrorRate(double errorRate) { this.errorRate = errorRate; }
        
        public Map<String, AtomicLong> getMethodCalls() { return methodCalls; }
        public void setMethodCalls(Map<String, AtomicLong> methodCalls) { this.methodCalls = methodCalls; }
        
        public Map<String, Double> getAverageExecutionTime() { return averageExecutionTime; }
        public void setAverageExecutionTime(Map<String, Double> averageExecutionTime) { this.averageExecutionTime = averageExecutionTime; }
        
        public Map<String, AtomicLong> getMethodErrors() { return methodErrors; }
        public void setMethodErrors(Map<String, AtomicLong> methodErrors) { this.methodErrors = methodErrors; }
        
        public LocalDateTime getTimestamp() { return timestamp; }
        public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
    }
}
